<!--
 * @Author: 九璃怀特 1599130621@qq.com
 * @Date: 2023-12-25 14:03:54
 * @LastEditors: 九璃怀特 1599130621@qq.com
 * @LastEditTime: 2023-12-26 09:42:03
 * @FilePath: \zxi-surface-guide\src\components\BaseUI\scroll\scroll.vue
 * @Description: 
 -->
<script setup lang="ts">
import { onBeforeUnmount, onMounted, PropType, ref } from "vue";
import BScroll, { Options } from "@better-scroll/core";
import MouseWheel, { MouseWheelOptions } from "@better-scroll/mouse-wheel";
import ScrollBar, { ScrollbarOptions } from "@better-scroll/scroll-bar";
import Pullup from "@better-scroll/pull-up";
import { throttle } from "utils/index";
// import { throttle } from "utils";

BScroll.use(MouseWheel).use(ScrollBar).use(Pullup);

const props = defineProps({
  goBottom: {
    type: Boolean as PropType<boolean>,
    default: false,
  },
  scrollbar: {
    type: Object as PropType<ScrollbarOptions>,
    default: () => {
      return {
        fade: true,
        interactive: true,
      };
    },
  },
  preventDefault: {
    type: Boolean as PropType<boolean>,
    default: false,
  },

  mouseWheel: {
    type: Boolean as PropType<MouseWheelOptions>,
    default: true,
  },

  pullingUp: {
    type: Function as PropType<() => Promise<any>>,
    default: undefined,
  },
  bounce: {
    type: Boolean,
    default: true,
  },
});

const root = ref<HTMLDivElement>();

onMounted(() => {
  watchResize.observe(wrapper.value!);
  watchResize.observe(scrollRef.value!);
});

onBeforeUnmount(() => {
  watchResize.disconnect();
});

const scroll = ref<BScroll>();

const scrolldom = ref<HTMLDivElement>();

const scrollRef = ref<HTMLDivElement>();

const wrapper = ref<HTMLDivElement>();

const scrollOptions: Options = {
  bounce: props.bounce,
  probeType: 3,
  momentum: true,
  preventDefault: props.preventDefault,
  preventDefaultException: {
    tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|SPAN|DIV|LI|UL|P|IMG|TD|I)$/,
  },
  click: false,
  mouseWheel: props.mouseWheel,
  scrollbar: props.scrollbar,
  stopPropagation: false,
  pullUpLoad: {
    threshold: -65,
  },
  disableMouse: false,
  disableTouch: false,
};

const watchResize = new ResizeObserver(() => {
  throttleInit();
});

// 记录包围高度
const throttleInit = throttle(initScroll, 100);

function initScroll(): void {
  if (!wrapper.value) return;
  if (scroll.value === undefined) {

    scroll.value = new BScroll(scrolldom.value!, scrollOptions);
    // 注册滑到底部事件
    scroll.value.on("pullingUp", () => {
      if (props.pullingUp) {
        props
          .pullingUp()
          .then(() => {
            scroll.value!.finishPullUp();
          })
          .catch(() => {
            scroll.value!.finishPullUp();
          });
      }
    });
  } else {
    setTimeout(() => {
      if (wrapper.value) {
        // dom发生变化后刷新
        scroll.value!.refresh();
      }
    }, 100);
  }
  if (props.goBottom) {
    scroll.value.scrollTo(0, scroll.value.maxScrollY);
  }
}

function scrollBottom() {
  if (scroll.value) {
    scroll.value.scrollTo(0, scroll.value.maxScrollY);
  }
}

defineExpose({
  root,
  scrollBottom,
});
</script>
<template>
  <div class="pm-scroll" ref="scrollRef">
    <div class="scroll-container">
      <div
        class="scroll-father"
        ref="scrolldom"
        @touchstart.stop
        @mousedown.stop
        @wheel.stop
        @contextmenu.prevent
      >
        <div ref="wrapper">
          <div ref="root">
            <slot />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="less" scoped>
.pm-scroll{
  width: 100%;
  height: 100%;
}
.scroll-container {
  width: 100%;
  height: 100%;
  position: relative;
  .scroll-father {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    > div {
      width: 100%;
      > div {
        width: 100%;
      }
    }
  }
}
</style>
